﻿using OpenTK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LDLib
{
    /// <summary>
    /// Base class for all GUI elements.
    /// This can be used to draw textures on the GUI 
    /// without inheritance.
    /// </summary>
    public class GUIElement
    {
        /// <summary>
        /// Indicates whether or not this element is enable
        /// </summary>
        protected bool enabled = true;

        /// <summary>
        /// Gets or sets the enabled status of this elements
        /// </summary>
        public bool Enabled
        {
            get { return enabled; }
            set
            {
                this.enabled = value;
                if(enabled)
                {
                    GUI.guiElements.Add(this);
                }
                else
                {
                    GUI.guiElements.Remove(this);
                }
            }
        }

        /// <summary>
        /// Screen position of this element
        /// </summary>
        protected Vector2 position;

        /// <summary>
        /// Clip position of this element
        /// </summary>
        protected Vector2 clipPosition;

        /// <summary>
        /// Gets or sets the screen position of this element.
        /// Note that (0, 0) is the bottom-left corner of the screen.
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            set
            {
                this.position = value;
                Vector2 scrSize = new Vector2(Properties.ScreenWidth, Properties.ScreenHeight);
                clipPosition = position - scrSize / 2f;
                clipPosition.X /= scrSize.X / 2f;
                clipPosition.Y /= scrSize.Y / 2f;
            }
        }

        /// <summary>
        /// Screen size of this element
        /// </summary>
        protected Vector2 size;

        /// <summary>
        /// Clip size of this element
        /// </summary>
        protected Vector2 clipSize;

        /// <summary>
        /// Gets or sets the screen size of this element.
        /// </summary>
        public Vector2 Size
        {
            get { return size; }
            set
            {
                this.size = value;
                Vector2 scrSize = new Vector2(Properties.ScreenWidth, Properties.ScreenHeight);
                clipSize = new Vector2(size.X / scrSize.X, size.Y / scrSize.Y) * 2f;
            }
        }

        /// <summary>
        /// Color of this element. This can be used
        /// to tint textures. 
        /// </summary>
        public Vector4 color = Vector4.One;

        /// <summary>
        /// Texture ID of the texture used for this element
        /// </summary>
        public int texture = -1;

        /// <summary>
        /// Depth indicator of this element
        /// </summary>
        public float Depth { get; set; }

        /// <summary>
        /// Z-rotation of this element
        /// </summary>
        public float rotation = 0f;

        /// <summary>
        /// Offset of the rotation. If (0, 0), the element
        /// is rotated around its center position.
        /// </summary>
        public Vector2 rotationOffset = Vector2.Zero;

        /// <summary>
        /// Transformation matrix
        /// </summary>
        protected Matrix4 matrix = Matrix4.Identity;

        /// <summary>
        /// Constructs a new GUI element
        /// </summary>
        public GUIElement()
        {
            Size = new Vector2(64, 64);
            Position = new Vector2(32, 32);
        }

        /// <summary>
        /// Updates this GUI element
        /// </summary>
        /// <param name="p">Time since last call</param>
        public virtual void Update(double p)
        {
            if (!enabled) return;

            if (rotation == 0f) matrix = Matrix4.Scale(clipSize.X, clipSize.Y, 1f) * Matrix4.CreateTranslation(clipPosition.X, clipPosition.Y, Depth);
            else
            {
                if (rotationOffset == Vector2.Zero)
                {
                    matrix = Matrix4.Scale(clipSize.X, clipSize.Y, 1f) *
                             Matrix4.CreateFromAxisAngle(Vector3.UnitZ, rotation) *
                             Matrix4.CreateTranslation(clipPosition.X, clipPosition.Y, Depth);
                }
                else
                {
                    matrix = Matrix4.Scale(clipSize.X, clipSize.Y, 1f) *
                             Matrix4.CreateTranslation(rotationOffset.X, rotationOffset.Y, 0f) *
                             Matrix4.CreateFromAxisAngle(Vector3.UnitZ, rotation) *
                             Matrix4.CreateTranslation(-rotationOffset.X, -rotationOffset.Y, 0f) *
                             Matrix4.CreateTranslation(clipPosition.X, clipPosition.Y, Depth);
                }
            }
        }

        /// <summary>
        /// Renders this element
        /// </summary>
        internal virtual void Render()
        {
            if (!enabled) return;

            Shader.currentShader.Set("world", matrix);
            Shader.currentShader.Set("diffuseColor", color);
            Shader.currentShader.Set("colorMap", texture);
            GUI.mesh.RenderMesh();
        }
    }
}
